// ChatClientDlg.cpp : implementation file
//

#include "stdafx.h"
#include "ChatClient.h"
#include "ChatClientDlg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#endif


// CChatClientDlg dialog




CChatClientDlg::CChatClientDlg(CWnd* pParent /*=NULL*/)
	: CDialog(CChatClientDlg::IDD, pParent)
{
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}

void CChatClientDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	DDX_Control(pDX, IDC_LIST_HISTORY_BOARD, m_HisoricalBoard);
	DDX_Text(pDX, IDC_EDIT_INTEXT, m_strInMessage);
	DDX_Control(pDX, IDC_LIST_USERS, m_UsersBoard);
}

void CChatClientDlg::OnOK()
{
}

BOOL CChatClientDlg::PreTranslateMessage(MSG* pMsg)
{
	switch( pMsg->message )
	{
	case WM_KEYDOWN:

		switch(pMsg->wParam)
		{
		case VK_RETURN:
			{
				//manage focus of input edit
				BOOL bCtrlKeyDown = ((GetKeyState(VK_CONTROL) & ~1) != 0);
				if(FALSE == bCtrlKeyDown && GetDlgItem(IDC_EDIT_INTEXT) == GetFocus())
				{			
					SendMessage(WM_COMMAND,IDC_BUTTON_SEND,(LPARAM)GetDlgItem(IDC_BUTTON_SEND)->m_hWnd);
					GetDlgItem(IDC_EDIT_INTEXT)->SetFocus();
				}
			}			
			break;
		case VK_INSERT:
			{
				//ignore Shift+insert
				BOOL bShiftKeyDown = ((GetKeyState(VK_SHIFT) & ~1) != 0);
				if(TRUE == bShiftKeyDown)
					return TRUE;
			}
			break;
		case 'V':
			{
				//ignore Ctrl+V
				BOOL bCtrlKeyDown = ((GetKeyState(VK_CONTROL) & ~1) != 0);
				if(TRUE == bCtrlKeyDown)
					return TRUE;
			}
			break;
		default:
			return CDialog::PreTranslateMessage(pMsg);
			break;
		}
		break;
	case WM_RBUTTONDOWN:
		//disable right click
		return TRUE;
		break;
	default:
		return CDialog::PreTranslateMessage(pMsg);
		break;
	}

	return CDialog::PreTranslateMessage(pMsg);
}

void CChatClientDlg::AddString(const CString& strMessage)
{
	m_HisoricalBoard.SetSel(-1,-1);
	CHARFORMAT cf;
	cf.cbSize = sizeof(CHARFORMAT);
	cf.dwMask = CFM_COLOR;
	m_HisoricalBoard.GetSelectionCharFormat(cf);
	if (cf.dwEffects & CFE_AUTOCOLOR)
		cf.dwEffects ^= CFE_AUTOCOLOR;
	cf.crTextColor = GetMessageColor(strMessage);
	m_HisoricalBoard.SetSelectionCharFormat(cf);

	CString strString = strMessage + _T("\r\n");
	m_HisoricalBoard.ReplaceSel(strString);
}

COLORREF CChatClientDlg::GetMessageColor(const CString& strMessage)
{
	if(GetFrom(strMessage) == UserName())
		return CChCSettings::Instance()->ColorFromMessages();

	if(GetTo(strMessage) == UserName())
		return CChCSettings::Instance()->ColorToMessages();

	if(GetTo(strMessage) == _T("All"))
		return CChCSettings::Instance()->ColorToAllMessages();

	if(TRUE == IsSystem(strMessage))
		return CChCSettings::Instance()->ColorSystemMessages();

	return 0;
}

BOOL CChatClientDlg::IsSystem(const CString& strMessage)
{
	CString strUserName = strMessage;
	return strUserName.Find(_T("System:"),0) >= 0;
}

CString CChatClientDlg::GetTo(const CString& strMessage)
{
	CString strUserName = strMessage;
	int nPos = strUserName.Find(_T(":"),0);

	if(nPos>0)
		strUserName.Truncate(nPos);
	nPos = strUserName.Find(_T("to"));

	if(nPos>0)
	{
		strUserName = strUserName.Right(strUserName.GetLength() - nPos - 3);
		strUserName.TrimLeft();
		strUserName.TrimRight();
		return strUserName;
	}

	return _T("");
}

CString CChatClientDlg::GetFrom(const CString& strMessage)
{
	CString strUserName = strMessage;
	int nPos = strUserName.Find(_T(":"),0);

	if(nPos>0)
		strUserName.Truncate(nPos);
	nPos = strUserName.Find(_T("to"));

	if(nPos>0)
		strUserName.Truncate(nPos);
	strUserName.TrimLeft();
	strUserName.TrimRight();

	return strUserName;
}

BEGIN_MESSAGE_MAP(CChatClientDlg, CDialog)
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
	ON_COMMAND(ID_FILE_CONNECT, &CChatClientDlg::OnFileConnect)
	ON_COMMAND(ID_FILE_DISCONNECT, &CChatClientDlg::OnFileDisconnect)
	ON_MESSAGE(CHM_ADDMESSAGE,&CChatClientDlg::OnAddMessage)
	ON_MESSAGE(CHM_CONNECTED,&CChatClientDlg::OnConnected)	
	ON_MESSAGE(CHM_SERVER_CLOSE_CONNECT, &CChatClientDlg::OnServerCloseConnection)
	ON_MESSAGE(CHM_SERVER_BAD_LOGIN,&CChatClientDlg::OnBadLogin)
	ON_MESSAGE(CHM_SERVER_ADD_USER, &CChatClientDlg::OnAddUser)
	ON_MESSAGE(CHM_SERVER_REMOVE_USER, &CChatClientDlg::OnRemoveUser)
	ON_BN_CLICKED(IDC_BUTTON_SEND, &CChatClientDlg::OnBnClickedButtonSend)
	ON_COMMAND(ID_FILE_CONNECTION_SETINGS, &CChatClientDlg::OnFileConnectionSetings)
	ON_COMMAND(ID_FILE_EXIT, &CChatClientDlg::OnFileExit)
	ON_COMMAND(ID_FILE_APPERANCE, &CChatClientDlg::OnFileApperance)
	ON_COMMAND(ID_HELP_ABOUT, &CChatClientDlg::OnHelpAbout)
END_MESSAGE_MAP()

BEGIN_EASYSIZE_MAP(CChatClientDlg)
	EASYSIZE(IDC_LIST_HISTORY_BOARD, ES_BORDER, ES_BORDER, ES_BORDER, ES_BORDER, 0)
	EASYSIZE(IDC_LIST_USERS, IDC_LIST_HISTORY_BOARD, ES_BORDER, ES_BORDER, ES_BORDER, 0)
	EASYSIZE(IDC_EDIT_INTEXT, ES_BORDER, IDC_LIST_HISTORY_BOARD, ES_BORDER, ES_BORDER, 0)
	EASYSIZE(IDC_BUTTON_SEND, ES_KEEPSIZE, IDC_EDIT_INTEXT, ES_BORDER, ES_BORDER, 0)
END_EASYSIZE_MAP


// CChatClientDlg message handlers
BOOL CChatClientDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Set the icon for this dialog.  The framework does this automatically
	//  when the application's main window is not a dialog
	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	CString strTitle = _T("Chat Client - ");
	strTitle += m_strUserName;
	strTitle += _T(" - Disconnected");
	SetWindowText(strTitle);
	m_UsersBoard.AddString(_T("All"));
	m_UsersBoard.SelectString(-1,_T("All"));

	((CEdit*)GetDlgItem(IDC_EDIT_INTEXT))->SetLimitText(255);

	INIT_EASYSIZE;

	PostMessage(WM_COMMAND,MAKELONG(ID_FILE_CONNECT,0),0);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CChatClientDlg::OnPaint()
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

// The system calls this function to obtain the cursor to display while the user drags
//  the minimized window.
HCURSOR CChatClientDlg::OnQueryDragIcon()
{
	return static_cast<HCURSOR>(m_hIcon);
}

/************************************************************************/
/* Menu events                                                          */
/************************************************************************/

void CChatClientDlg::OnFileConnect()
{
	CChCConnect::Initialize(UserName());
	CChCSettings *pSettings = CChCSettings::Instance();
	CChCConnect::Instance()->Connect(pSettings->HostName(),pSettings->Port());
}

void CChatClientDlg::OnFileDisconnect()
{ 
	CString strBye(_T("bye"));
	CChCConnect::Instance()->Send((LPCTSTR)strBye,(strBye.GetLength()+1)*sizeof(TCHAR));
	CChCConnect::Instance()->ShutDown();
	CChCConnect::Instance()->Close();
	CChCConnect::Uninitialize();

	AddString(_T("Disconnected"));
	CString strTitle = _T("Chat Client - ");
	strTitle += m_strUserName;
	strTitle += _T(" - Disconnected");
	SetWindowText(strTitle);

	GetDlgItem(IDC_LIST_HISTORY_BOARD)->SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);
}

/************************************************************************/
/* User messages                                                        */
/************************************************************************/
LRESULT  CChatClientDlg::OnAddMessage(WPARAM wParam, LPARAM lParam)
{
	AddString((const TCHAR*)lParam);
	GetDlgItem(IDC_LIST_HISTORY_BOARD)->SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);
	return 0;
}

LRESULT  CChatClientDlg::OnConnected(WPARAM wParam, LPARAM lParam)
{
	AddString(_T("System: Connected"));
	CString strTitle = _T("Chat Client - ");
	strTitle += m_strUserName;
	strTitle += _T(" - Connected");
		SetWindowText(strTitle);

	GetDlgItem(IDC_LIST_HISTORY_BOARD)->SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);

	return 0;
}

LRESULT  CChatClientDlg::OnServerCloseConnection(WPARAM wParam, LPARAM lParam)
{
	AddString(_T("System: Server close connection"));
	CString strTitle = _T("Chat Client - ");
	strTitle += m_strUserName;
	strTitle += _T(" - Disconnected");
		SetWindowText(strTitle);
	CChCConnect::Uninitialize();

	GetDlgItem(IDC_LIST_HISTORY_BOARD)->SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);

	m_UsersBoard.ResetContent();
	m_UsersBoard.AddString(_T("All"));
	m_UsersBoard.SelectString(-1,_T("All"));

	return 0;
}

LRESULT CChatClientDlg::OnBadLogin(WPARAM wParam, LPARAM lParam)
{
	//user authentication
	CString strUserName;
	int nRet = AfxMessageBox(_T("Bad login. Are you want use PC name as you login?"),MB_YESNOCANCEL);
	switch(nRet)
	{
	case IDYES:
		{
			//get pc name for login
			DWORD dwSize = 1024;
			TCHAR strPCName[1024];
			if(FALSE == GetComputerName(strPCName,&dwSize))
			{
				AfxMessageBox(_T("Can't get PC name"));
				return 0xdead;
			}
			UserName(strPCName);
		}
		break;
	case IDNO:
		{
			CChCAuthorizationDlg dlg;
			if(IDCANCEL == dlg.DoModal())
				OnCancel();
			UserName(dlg.UserName());
		}
		break;
	case IDCANCEL:
		OnCancel();
		break;
	default:
		ASSERT(0);
		OnCancel();
		break;
	}

	CChCConnect::Initialize(UserName());
	CChCSettings *pSettings = CChCSettings::Instance();
	CChCConnect::Instance()->Connect(pSettings->HostName(),pSettings->Port());

	return 0;
}

LRESULT  CChatClientDlg::OnAddUser(WPARAM wParam, LPARAM lParam)
{
	m_UsersBoard.AddString((const TCHAR*)lParam);
	return 0;
}

LRESULT  CChatClientDlg::OnRemoveUser(WPARAM wParam, LPARAM lParam)
{
	int nPos = m_UsersBoard.FindString(-1,(const TCHAR*)lParam);
	if(nPos >=0)
		m_UsersBoard.DeleteString(nPos);

	return 0;
}


void CChatClientDlg::OnBnClickedButtonSend()
{
	UpdateData(TRUE);
	if(FALSE == m_strInMessage.IsEmpty())
	{
		CString strMsg = m_strUserName;
		if(0 <= m_UsersBoard.GetCurSel())
		{
			strMsg += _T(" to ");
			CString strTo;
		
			m_UsersBoard.GetText(m_UsersBoard.GetCurSel(),strTo);	
			int nPos = strTo.Find(_T(":"));

			if(nPos>0)
				strTo.Truncate(nPos);
			nPos = strTo.Find(_T("to"));

			if(nPos>0)
				strTo.Truncate(nPos);

			strMsg += strTo;
		}

		strMsg += _T(" : ");
		strMsg += m_strInMessage;
		int nRet = CChCConnect::Instance()->Send((LPCTSTR)strMsg,(strMsg.GetLength()+1)*sizeof(TCHAR));

		if(0 >= nRet)
		{
			AddString(_T("System: Can't send message. Try reconnect"));
			GetDlgItem(IDC_LIST_HISTORY_BOARD)->SendMessage(WM_VSCROLL, SB_BOTTOM, NULL);
		}
		else
		{
			m_strInMessage = _T("");
			UpdateData(FALSE);
		}
	}
}

void CChatClientDlg::OnFileConnectionSetings()
{
	CChCConnectionSettingsDlg::SetupSettings();
}

void CChatClientDlg::OnFileExit()
{
	OnCancel();
}

void CChatClientDlg::OnFileApperance()
{
	CChCAppernaceDlg::SetupApperance();
}

void CChatClientDlg::OnSize(UINT nType, int cx, int cy)
{
	UPDATE_EASYSIZE;
	CDialog::OnSize(nType,cx,cy);
}

void CChatClientDlg::OnHelpAbout()
{
	AfxMessageBox(_T("Version 1.0.0.3\n Copyright"),MB_ICONINFORMATION|MB_OK)	;
}
